﻿using System;

namespace Loki.Commands
{
    /// <summary>
    /// Loki command handlers.
    /// </summary>
    /// <remarks>Command handlers are stored as weak references in command service. Use this class and hold a reference on it in your command listener class.</remarks>
    public sealed class LokiCommandHandler : ICommandHandler, IDisposable
    {
        /// <summary>
        /// Prevents a default instance of the <see cref="LokiCommandHandler"/> class from being created.
        /// </summary>
        private LokiCommandHandler()
        {
        }

        public static LokiCommandHandler Create(
            Action<object, CanExecuteCommandEventArgs> P_CanExecute,
            Action<object, CommandEventArgs> P_Execute)
        {
            return Create(P_CanExecute, P_Execute, null, null);
        }

        public static LokiCommandHandler Create(
            Action<object, CanExecuteCommandEventArgs> P_CanExecute,
            Action<object, CommandEventArgs> P_Execute,
            ICommandAware P_State)
        {
            return Create(P_CanExecute, P_Execute, P_State, null);
        }

        /// <summary>
        /// Creates a new command handler with the specified delegates.
        /// </summary>
        /// <param name="P_CanExecute">The can execute functor.</param>
        /// <param name="P_Execute">The execute functor.</param>
        /// <param name="P_State">The state callback.</param>
        /// <param name="P_ConfirmDelegate">The confirm functor.</param>
        public static LokiCommandHandler Create(
            Action<object, CanExecuteCommandEventArgs> P_CanExecute,
            Action<object, CommandEventArgs> P_Execute,
            ICommandAware P_State,
            Func<CommandEventArgs, bool> P_ConfirmDelegate)
        {
            LokiCommandHandler L_Handler = new LokiCommandHandler();
            try
            {
                L_Handler.CanExecute = new EventHandler<CanExecuteCommandEventArgs>(P_CanExecute);
                L_Handler.Execute = new EventHandler<CommandEventArgs>(P_Execute);
                L_Handler.State = P_State;
                L_Handler.ConfirmDelegate = P_ConfirmDelegate;
                return L_Handler;
            }
            catch
            {
                L_Handler.Dispose();
                throw;
            }
        }

        /// <summary>
        /// Gets the CanExecute command handler.
        /// </summary>
        public EventHandler<CanExecuteCommandEventArgs> CanExecute
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the Execute command handler.
        /// </summary>
        public EventHandler<CommandEventArgs> Execute
        {
            get;
            private set;
        }

        public ICommandAware State
        {
            get;
            private set;
        }

        public Func<CommandEventArgs, bool> ConfirmDelegate
        {
            get;
            private set;
        }

        #region IDisposable
        /// <summary>
        /// Releases all resources used by an instance of the <see cref="LokiCommandHandler" /> class.
        /// </summary>
        /// <remarks>
        /// This method calls the virtual <see cref="Dispose(bool)" /> method, passing in <strong>true</strong>, and then suppresses 
        /// finalization of the instance.
        /// </remarks>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        ~LokiCommandHandler()
        {
            Dispose(false);
        }

        /// <summary>
        /// Releases the unmanaged resources used by an instance of the <see cref="LokiCommandHandler" /> class and optionally releases the managed resources.
        /// </summary>
        /// <param name="P_Disposing">Set <strong>true</strong> to release both managed and unmanaged resources; <strong>false</strong> to release only unmanaged resources.</param>
        private void Dispose(bool P_Disposing)
        {
            if (P_Disposing)
            {
                Execute = null;
                CanExecute = null;
                State = null;
            }
        }
        #endregion

        #region IEquatable<ICommandHandler> Members

        public bool Equals(ICommandHandler P_Other)
        {
            if (P_Other == null)
            {
                return false;
            }
            else
            {
                return P_Other.CanExecute == CanExecute
                    && P_Other.Execute == Execute
                    && P_Other.State == State
                    && P_Other.ConfirmDelegate == ConfirmDelegate;
            }
        }

        #endregion
    }
}
